/*
 * Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.xuexiang.xui_lib.component.tabbar;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrHelper;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DependentLayout;
import ohos.agp.components.PageSlider;
import ohos.agp.components.PageSliderProvider;
import ohos.agp.components.ScrollView;
import ohos.agp.components.Text;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.render.Canvas;
import ohos.agp.render.ColorMatrix;
import ohos.agp.render.Paint;
import ohos.agp.text.Font;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.utils.Rect;
import ohos.agp.utils.TextAlignment;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;

import com.xuexiang.xui_lib.ResourceTable;
import com.xuexiang.xui_lib.util.AttrValue;
import com.xuexiang.xui_lib.util.ColorUtils;
import com.xuexiang.xui_lib.util.ElementHelper;
import com.xuexiang.xui_lib.util.LogUtils;
import com.xuexiang.xui_lib.util.SizeUtils;
import com.xuexiang.xui_lib.util.Utils;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

public class TabSegment extends ScrollView implements Component.EstimateSizeListener {
    private static final String TAG = "TabSegment";
    private static final int ID_TAB_ITEM_VIEW = 0XFF;

    // mode: 自适应宽度+滚动 / 均分
    public static final int MODE_SCROLLABLE = 0;
    public static final int MODE_FIXED = 1;
    // icon position
    public static final int ICON_POSITION_LEFT = 0;
    public static final int ICON_POSITION_TOP = 1;
    public static final int ICON_POSITION_RIGHT = 2;
    public static final int ICON_POSITION_BOTTOM = 3;

    private static final int NO_POSITION = -1;
    private boolean isModeFixedFirst = true;
    /**
     * listener
     */
    private final ArrayList<OnTabSelectedListener> mSelectedListeners = new ArrayList<>();
    private Container mContentLayout;

    private int mCurrentSelectedIndex = NO_POSITION;
    private int mPendingSelectedIndex = NO_POSITION;

    /**
     * item的默认字体大小
     */
    private int mTabTextSize;
    /**
     * 是否有Indicator
     */
    private boolean mHasIndicator = true;
    /**
     * Indicator高度
     */
    private int mIndicatorHeight;
    /**
     * indicator在顶部
     */
    private boolean mIndicatorTop = false;
    /**
     * indicator采用drawable
     */
    private Element mIndicatorDrawable;
    /**
     * indicator宽度跟随内容宽度
     */
    private boolean mIsIndicatorWidthFollowContent = true;

    /**
     * indicator rect, draw directly
     */
    private Rect mIndicatorRect = null;

    /**
     * indicator paint, draw directly
     */
    private Paint mIndicatorPaint = null;

    /**
     * item normal color
     */
    private int mNormalColor;
    /**
     * item selected color
     */
    private int mSelectedColor;
    /**
     * item icon的默认位置
     */
    @IconPosition
    private int mDefaultTabIconPosition;
    /**
     * TabSegmentMode
     */
    @Mode
    private int mMode = MODE_FIXED;
    /**
     * ScrollMode下item的间隙
     */
    private int mItemSpaceInScrollMode;
    /**
     * typeface
     */
    private TypefaceProvider mTypefaceProvider;

    /**
     * 记录 ViewPager 的 scrollState
     */
    private int mViewPagerScrollState = PageSlider.SCROLL_IDLE_STAGE;

    private Animator mSelectAnimator;
    private OnTabClickListener mOnTabClickListener;
    protected ClickedListener mTabOnClickListener = new ClickedListener() {
        @Override
        public void onClick(Component v) {
            if (mSelectAnimator != null || mViewPagerScrollState != PageSlider.SCROLL_IDLE_STAGE) {
                return;
            }
            int index = (int) v.getTag();
            Tab model = getAdapter().getItem(index);
            if (model != null) {
                selectTab(index, !mHasIndicator && !model.isDynamicChangeIconColor(), true);
            }
            if (mOnTabClickListener != null) {
                mOnTabClickListener.onTabClick(index);
            }
        }
    };
    /**
     * 与ViewPager的协同工作
     */
    private PageSlider mViewPager;
    private PageSliderProvider mPagerAdapter;
    //    private DataSetObserver mPagerAdapterObserver;
    private PageSlider.PageChangedListener mOnPageChangeListener;
    private OnTabSelectedListener mViewPagerSelectedListener;
    //    private AdapterChangeListener mAdapterChangeListener;
    private boolean mIsInSelectTab = false;

   /* public TabSegment(Context context) {
        this(context, null);
    }*/

    /*public TabSegment(Context context, boolean hasIndicator) {
        this(context, null);
        mHasIndicator = hasIndicator;
    }*/

    public TabSegment(Context context, AttrSet attrs) {
        this(context, attrs, null);
    }

    public TabSegment(Context context, AttrSet attrs, String defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttrSet attrs) {
        setLayoutRefreshedListener(new LayoutRefreshedListener() {
            @Override
            public void onRefreshed(Component component) {
                if (mCurrentSelectedIndex != NO_POSITION && mMode == MODE_SCROLLABLE) {
                    TabAdapter tabAdapter = getAdapter();
                    final TabItemView view = tabAdapter.getViews().get(mCurrentSelectedIndex);
                    if (getScrollValue(AXIS_X) > view.getLeft()) {
                        scrollTo(view.getLeft(), 0);
                    } else {
                        int realWidth = getWidth() - getPaddingRight() - getPaddingLeft();
                        if (getScrollValue(AXIS_X) + realWidth < view.getRight()) {
                            scrollBy(view.getRight() - realWidth - getScrollValue(AXIS_X), 0);
                        }
                    }
                }
            }
        });

        mSelectedColor = AttrValue.get(attrs, "ts_selected_color",
            new Color(context.getColor(ResourceTable.Color_colorPrimary))).getValue();
        mNormalColor = AttrValue.get(attrs, "ts_normal_color",
            new Color(context.getColor(ResourceTable.Color_xui_config_color_gray_5))).getValue();
        mHasIndicator = AttrValue.get(attrs, "ts_has_indicator", true);
        mIndicatorHeight = AttrValue.getDimension(attrs, "ts_indicator_height", SizeUtils.vp2px(context, 2));
        mTabTextSize = AttrValue.getDimension(attrs, "ts_text_size", 16);
        mIndicatorTop = AttrValue.get(attrs, "ts_indicator_top", false);
        mDefaultTabIconPosition = AttrValue.get(attrs, "ts_icon_position", ICON_POSITION_LEFT);
        mMode = AttrValue.get(attrs, "ts_mode", MODE_FIXED);
        mItemSpaceInScrollMode = AttrValue.getDimension(attrs, "ts_space", SizeUtils.vp2px(context, 10));
        String typefaceProviderName = AttrValue.get(attrs, "ts_typeface_provider", "");

        mContentLayout = new Container(context);
//        mContentLayout.setOrientation(Component.HORIZONTAL);
        addComponent(mContentLayout, new ComponentContainer.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT,
            ComponentContainer.LayoutConfig.MATCH_PARENT));

        createTypefaceProvider(context, typefaceProviderName);
    }

    private void createTypefaceProvider(Context context, String className) {
        if (Utils.isNullOrEmpty(className)) {
            return;
        }
        className = className.trim();
        if (className.length() == 0) {
            return;
        }
        className = getFullClassName(context, className);
        try {
            ClassLoader classLoader;
            classLoader = this.getClass().getClassLoader();
            Class<? extends TypefaceProvider> providerClass =
                classLoader.loadClass(className).asSubclass(TypefaceProvider.class);
            Constructor<? extends TypefaceProvider> constructor;
            try {
                constructor = providerClass.getConstructor();
            } catch (NoSuchMethodException e) {
                throw new IllegalStateException("Error creating TypefaceProvider " + className, e);
            }
            constructor.setAccessible(true);
            mTypefaceProvider = constructor.newInstance();
        } catch (ClassNotFoundException e) {
            throw new IllegalStateException("Unable to find TypefaceProvider " + className, e);
        } catch (InvocationTargetException e) {
            throw new IllegalStateException("Could not instantiate the TypefaceProvider: " + className, e);
        } catch (InstantiationException e) {
            throw new IllegalStateException("Could not instantiate the TypefaceProvider: " + className, e);
        } catch (IllegalAccessException e) {
            throw new IllegalStateException("Cannot access non-public constructor " + className, e);
        } catch (ClassCastException e) {
            throw new IllegalStateException("Class is not a TypefaceProvider " + className, e);
        }
    }

    private String getFullClassName(Context context, String className) {
        if (className.charAt(0) == '.') {
            return context.getBundleName() + className;
        }
        return className;
    }

    public void setTypefaceProvider(TypefaceProvider typefaceProvider) {
        mTypefaceProvider = typefaceProvider;
    }

    public TabSegment addTab(Tab item) {
        mContentLayout.getTabAdapter().addItem(item);
        return this;
    }

    private TabAdapter getAdapter() {
        return mContentLayout.getTabAdapter();
    }

    public void setTabTextSize(int tabTextSize) {
        mTabTextSize = tabTextSize;
    }

    /**
     * 清空已经存在的 Tab。
     * 一般先调用本方法清空已加上的 Tab, 然后重新 {@link #addTab(Tab)} 添加新的 Tab, 然后通过 {@link #notifyDataChanged()} 通知变动
     */
    public void reset() {
        mContentLayout.getTabAdapter().clear();
        mCurrentSelectedIndex = NO_POSITION;
        if (mSelectAnimator != null) {
            mSelectAnimator.cancel();
            mSelectAnimator = null;
        }
    }

    /**
     * 通知 TabSegment 数据变动。
     * 一般先调用 {@link #reset()} 清空已加上的 Tab, 然后重新 {@link #addTab(Tab)} 添加新的 Tab, 然后通过本方法通知变动
     */
    public void notifyDataChanged() {
        getAdapter().setup();
        populateFromPagerAdapter(false);
    }

    public void addOnTabSelectedListener(OnTabSelectedListener listener) {
        if (!mSelectedListeners.contains(listener)) {
            mSelectedListeners.add(listener);
        }
    }

    public void setItemSpaceInScrollMode(int itemSpaceInScrollMode) {
        mItemSpaceInScrollMode = itemSpaceInScrollMode;
    }

    /**
     * 设置 indicator 为自定义的 Drawable(默认跟随 Tab 的 selectedColor)
     *
     * @param indicatorDrawable
     */
    public void setIndicatorDrawable(Element indicatorDrawable) {
        mIndicatorDrawable = indicatorDrawable;
        if (indicatorDrawable != null) {
            mIndicatorHeight = indicatorDrawable.getHeight();
        }
        mContentLayout.invalidate();
    }

    /**
     * 设置 indicator的宽度是否随内容宽度变化
     *
     * @param indicatorWidthFollowContent indicatorWidthFollowContent
     */
    public void setIndicatorWidthAdjustContent(boolean indicatorWidthFollowContent) {
        if (mIsIndicatorWidthFollowContent != indicatorWidthFollowContent) {
            mIsIndicatorWidthFollowContent = indicatorWidthFollowContent;
            mContentLayout.postLayout();
        }
    }

    /**
     * 设置 indicator 的位置
     *
     * @param isIndicatorTop true 时表示 indicator 位置在 Tab 的上方, false 时表示在下方
     */
    public void setIndicatorPosition(boolean isIndicatorTop) {
        if (mIndicatorTop != isIndicatorTop) {
            mIndicatorTop = isIndicatorTop;
            mContentLayout.invalidate();
        }
    }

    /**
     * 设置是否需要显示 indicator
     *
     * @param hasIndicator 是否需要显示 indicator
     */
    public void setHasIndicator(boolean hasIndicator) {
        if (mHasIndicator != hasIndicator) {
            mHasIndicator = hasIndicator;
            invalidate();
        }

    }

    public int getMode() {
        return mMode;
    }

    public void setMode(@Mode int mode) {
        if (mMode != mode) {
            mMode = mode;
            mContentLayout.invalidate();
        }
    }

    public void removeOnTabSelectedListener(OnTabSelectedListener listener) {
        mSelectedListeners.remove(listener);
    }

    public void clearOnTabSelectedListeners() {
        mSelectedListeners.clear();
    }

    public void setupWithViewPager(PageSlider viewPager) {
        setupWithViewPager(viewPager, true);
    }

    public void setupWithViewPager(PageSlider viewPager, boolean useAdapterTitle) {
        setupWithViewPager(viewPager, useAdapterTitle, true);
    }

    /**
     * setupWithViewPager
     *
     * @param viewPager 需要关联的 ViewPager。
     * @param useAdapterTitle 自动根据ViewPager的adapter.getTitle取值。
     * @param autoRefresh adapter有更改时，刷新TabSegment。
     */
    public void setupWithViewPager(final PageSlider viewPager, boolean useAdapterTitle, boolean autoRefresh) {
        if (mViewPager != null) {
            // If we've already been setup with a ViewPager, remove us from it
            if (mOnPageChangeListener != null) {
                mViewPager.removePageChangedListener(mOnPageChangeListener);
            }
        }

        if (mViewPagerSelectedListener != null) {
            // If we already have a tab selected listener for the ViewPager, remove it
            removeOnTabSelectedListener(mViewPagerSelectedListener);
            mViewPagerSelectedListener = null;
        }

        if (viewPager != null) {
            mViewPager = viewPager;

            // Add our custom OnPageChangeListener to the ViewPager
            if (mOnPageChangeListener == null) {
                mOnPageChangeListener = new TabLayoutOnPageChangeListener(this);
            }
            viewPager.addPageChangedListener(mOnPageChangeListener);

            // Now we'll add a tab selected listener to set ViewPager's current item
            mViewPagerSelectedListener = new ViewPagerOnTabSelectedListener(viewPager);
            addOnTabSelectedListener(mViewPagerSelectedListener);

            final PageSliderProvider adapter = viewPager.getProvider();
            if (adapter != null) {
                // Now we'll populate ourselves from the pager adapter, adding an observer if
                // autoRefresh is enabled
                setPagerAdapter(adapter, useAdapterTitle, autoRefresh);
            }

            // Add a listener so that we're notified of any adapter changes
//            if (mAdapterChangeListener == null) {
//                mAdapterChangeListener = new AdapterChangeListener(useAdapterTitle);
//            }
//            mAdapterChangeListener.setAutoRefresh(autoRefresh);
//            viewPager.addOnAdapterChangeListener(mAdapterChangeListener);
        } else {
            // We've been given a null ViewPager so we need to clear out the internal state,
            // listeners and observers
            mViewPager = null;
            setPagerAdapter(null, false, false);
        }
    }

    private void dispatchTabSelected(int index) {
        for (int i = mSelectedListeners.size() - 1; i >= 0; i--) {
            mSelectedListeners.get(i).onTabSelected(index);
        }
    }

    private void dispatchTabUnselected(int index) {
        for (int i = mSelectedListeners.size() - 1; i >= 0; i--) {
            mSelectedListeners.get(i).onTabUnselected(index);
        }
    }

    private void dispatchTabReselected(int index) {
        for (int i = mSelectedListeners.size() - 1; i >= 0; i--) {
            mSelectedListeners.get(i).onTabReselected(index);
        }
    }

    private void dispatchTabDoubleTap(int index) {
        for (int i = mSelectedListeners.size() - 1; i >= 0; i--) {
            mSelectedListeners.get(i).onDoubleTap(index);
        }
    }

    /**
     * 设置 Tab 正常状态下的颜色
     *
     * @param defaultNormalColor defaultNormalColor
     */
    public void setDefaultNormalColor(int defaultNormalColor) {
        mNormalColor = defaultNormalColor;
    }

    /**
     * 设置 Tab 选中状态下的颜色
     *
     * @param defaultSelectedColor defaultSelectedColor
     */
    public void setDefaultSelectedColor(int defaultSelectedColor) {
        mSelectedColor = defaultSelectedColor;
    }

    /**
     * 设置Icon位置
     *
     * @param defaultTabIconPosition defaultTabIconPosition
     */
    public void setDefaultTabIconPosition(@IconPosition int defaultTabIconPosition) {
        mDefaultTabIconPosition = defaultTabIconPosition;
    }

    private void setViewPagerScrollState(int state) {
        mViewPagerScrollState = state;
        if (mViewPagerScrollState == PageSlider.SCROLL_IDLE_STAGE) {
            if (mPendingSelectedIndex != NO_POSITION && mSelectAnimator == null) {
                selectTab(mPendingSelectedIndex, true, false);
                mPendingSelectedIndex = NO_POSITION;
            }
        }
    }

    public void selectTab(int index) {
        selectTab(index, false, false);
    }

    public void selectTab(final int index, boolean noAnimation, boolean fromTabClick) {
        if (mIsInSelectTab) {
            return;
        }
        mIsInSelectTab = true;
        TabAdapter tabAdapter = getAdapter();
        List<TabItemView> listViews = tabAdapter.getViews();

        if (listViews.size() != tabAdapter.getSize()) {
            tabAdapter.setup();
            listViews = tabAdapter.getViews();
        }

        if (listViews.size() == 0 || listViews.size() <= index) {
            mIsInSelectTab = false;
            return;
        }

        if (mSelectAnimator != null || mViewPagerScrollState != PageSlider.SCROLL_IDLE_STAGE) {
            mPendingSelectedIndex = index;
            mIsInSelectTab = false;
            return;
        }
        if (mCurrentSelectedIndex == index) {
            if (fromTabClick) {
                // dispatch re select only when click tab
                dispatchTabReselected(index);
            }
            mIsInSelectTab = false;
            // invalidate mContentLayout to sure indicator is drawn if needed
            mContentLayout.invalidate();
            return;
        }

        if (mCurrentSelectedIndex > listViews.size()) {
            LogUtils.info(TAG, "selectTab: current selected index is bigger than views size.");
            mCurrentSelectedIndex = NO_POSITION;
        }

        // first time to select
        if (mCurrentSelectedIndex == NO_POSITION) {
            Tab model = tabAdapter.getItem(index);
            new EventHandler(EventRunner.getMainEventRunner()).postTask(new Runnable() {
                @Override
                public void run() {
                    layoutIndicator(model, true);
                }
            }, 100);
            Text selectedTv = listViews.get(index).getTextView();
            setTextViewTypeface(selectedTv, true);
            listViews.get(index).updateDecoration(model, true);
            dispatchTabSelected(index);
            mCurrentSelectedIndex = index;
            mIsInSelectTab = false;
            return;
        }

        final int prev = mCurrentSelectedIndex;
        final Tab prevModel = tabAdapter.getItem(prev);
        final TabItemView prevView = listViews.get(prev);
        final Tab nowModel = tabAdapter.getItem(index);
        final TabItemView nowView = listViews.get(index);

        if (noAnimation) {
            dispatchTabUnselected(prev);
            dispatchTabSelected(index);
            setTextViewTypeface(prevView.getTextView(), false);
            setTextViewTypeface(nowView.getTextView(), true);
            prevView.updateDecoration(prevModel, false);
            nowView.updateDecoration(nowModel, true);
            if (getScrollValue(AXIS_X) > nowView.getLeft()) {
                fluentScrollTo(nowView.getLeft(), 0);
            } else {
                int realWidth = getWidth() - getPaddingRight() - getPaddingLeft();
                if (getScrollValue(AXIS_X) + realWidth < nowView.getRight()) {
                    fluentScrollBy(nowView.getRight() - realWidth - getScrollValue(AXIS_X), 0);
                }
            }
            mCurrentSelectedIndex = index;
            mIsInSelectTab = false;
            layoutIndicator(nowModel, true);
            return;
        }

        final AnimatorValue animatorValue = new AnimatorValue();
        animatorValue.setCurveType(Animator.CurveType.LINEAR);
        animatorValue.setDuration(200);
        animatorValue.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float v) {
                float animValue = v;
                int preColor = ColorUtils.computeColor(getTabSelectedColor(prevModel), getTabNormalColor(prevModel), animValue);
                int nowColor = ColorUtils.computeColor(getTabNormalColor(nowModel), getTabSelectedColor(nowModel), animValue);
                prevView.setColorInTransition(prevModel, preColor);
                nowView.setColorInTransition(nowModel, nowColor);
                layoutIndicatorInTransition(prevModel, nowModel, animValue);
            }
        });
        animatorValue.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
                mSelectAnimator = animator;
            }

            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {
                mSelectAnimator = null;
                prevView.updateDecoration(prevModel, true);
                nowView.updateDecoration(nowModel, false);
                layoutIndicator(prevModel, true);
            }

            @Override
            public void onEnd(Animator animator) {
                mSelectAnimator = null;
                prevView.updateDecoration(prevModel, false);
                nowView.updateDecoration(nowModel, true);
                dispatchTabSelected(index);
                dispatchTabUnselected(prev);
                setTextViewTypeface(prevView.getTextView(), false);
                setTextViewTypeface(nowView.getTextView(), true);
                mCurrentSelectedIndex = index;
                if (mPendingSelectedIndex != NO_POSITION && mViewPagerScrollState == PageSlider.SCROLL_IDLE_STAGE) {
                    selectTab(mPendingSelectedIndex, true, false);
                    mPendingSelectedIndex = NO_POSITION;
                }
            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }
        });
        animatorValue.start();
        mIsInSelectTab = false;
    }

    private void layoutIndicator(Tab model, boolean invalidate) {
        if (model == null) {
            return;
        }
        if (mIndicatorRect == null) {
            mIndicatorRect = new Rect(model.contentLeft, 0,
                model.contentLeft + model.contentWidth, 0);
        } else {
            mIndicatorRect.left = model.contentLeft;
            mIndicatorRect.right = model.contentLeft + model.contentWidth;
        }
        if (mIndicatorPaint == null) {
            mIndicatorPaint = new Paint();
            mIndicatorPaint.setStyle(Paint.Style.FILL_STYLE);
        }
        mIndicatorPaint.setColor(new Color(getTabSelectedColor(model)));
        if (invalidate) {
            mContentLayout.invalidate();
        }
    }

    private void layoutIndicatorInTransition(Tab preModel, Tab targetModel, float offsetPercent) {
        final int leftDistance = targetModel.getContentLeft() - preModel.getContentLeft();
        final int widthDistance = targetModel.getContentWidth() - preModel.getContentWidth();
        final int targetLeft = (int) (preModel.getContentLeft() + leftDistance * offsetPercent);
        final int targetWidth = (int) (preModel.getContentWidth() + widthDistance * offsetPercent);
        if (mIndicatorRect == null) {
            mIndicatorRect = new Rect(targetLeft, 0, targetLeft + targetWidth, 0);
        } else {
            mIndicatorRect.left = targetLeft;
            mIndicatorRect.right = targetLeft + targetWidth;
        }

        if (mIndicatorPaint == null) {
            mIndicatorPaint = new Paint();
            mIndicatorPaint.setStyle(Paint.Style.FILL_STYLE);
        }
        int indicatorColor = ColorUtils.computeColor(
            getTabSelectedColor(preModel), getTabSelectedColor(targetModel), offsetPercent);
        mIndicatorPaint.setColor(new Color(indicatorColor));
        mContentLayout.invalidate();
    }

    private void setTextViewTypeface(Text tv, boolean selected) {
        if (mTypefaceProvider == null || tv == null) {
            return;
        }
        boolean isBold = selected ? mTypefaceProvider.isSelectedTabBold() : mTypefaceProvider.isNormalTabBold();
        tv.setFont(isBold ? Font.DEFAULT_BOLD : Font.DEFAULT);
    }

    public void updateIndicatorPosition(final int index, float offsetPercent) {
        if (mSelectAnimator != null || mIsInSelectTab || offsetPercent == 0) {
            return;
        }

        int targetIndex;
        if (offsetPercent < 0) {
            targetIndex = index - 1;
            offsetPercent = -offsetPercent;
        } else {
            targetIndex = index + 1;
        }

        TabAdapter tabAdapter = getAdapter();
        final List<TabItemView> listViews = tabAdapter.getViews();
        if (listViews.size() <= index || listViews.size() <= targetIndex) {
            return;
        }
        Tab preModel = tabAdapter.getItem(index);
        Tab targetModel = tabAdapter.getItem(targetIndex);
        TabItemView preView = listViews.get(index);
        TabItemView targetView = listViews.get(targetIndex);
        int preColor = ColorUtils.computeColor(getTabSelectedColor(preModel), getTabNormalColor(preModel), offsetPercent);
        int targetColor = ColorUtils.computeColor(getTabNormalColor(targetModel), getTabSelectedColor(targetModel), offsetPercent);
        preView.setColorInTransition(preModel, preColor);
        targetView.setColorInTransition(targetModel, targetColor);
        layoutIndicatorInTransition(preModel, targetModel, offsetPercent);
    }

    /**
     * 改变 Tab 的文案
     *
     * @param index Tab 的 index
     * @param text 新文案
     */
    public void updateTabText(int index, String text) {
        Tab model = getAdapter().getItem(index);
        if (model == null) {
            return;
        }
        model.setText(text);
        notifyDataChanged();
    }

    /**
     * 整个 Tab 替换
     *
     * @param index 需要被替换的 Tab 的 index
     * @param model 新的 Tab
     */
    public void replaceTab(int index, Tab model) {
        try {
            getAdapter().replaceItem(index, model);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public void setOnTabClickListener(OnTabClickListener onTabClickListener) {
        mOnTabClickListener = onTabClickListener;
    }

    private void setDrawable(Text tv, Element drawable, int iconPosition) {
        tv.setAroundElements(
            iconPosition == ICON_POSITION_LEFT ? drawable : null,
            iconPosition == ICON_POSITION_TOP ? drawable : null,
            iconPosition == ICON_POSITION_RIGHT ? drawable : null,
            iconPosition == ICON_POSITION_BOTTOM ? drawable : null
        );
    }

    private int getTabNormalColor(Tab item) {
        int color = item.getNormalColor();
        if (color == Tab.USE_TAB_SEGMENT) {
            color = mNormalColor;
        }
        return color;
    }

    private int getTabIconPosition(Tab item) {
        int iconPosition = item.getIconPosition();
        if (iconPosition == Tab.USE_TAB_SEGMENT) {
            iconPosition = mDefaultTabIconPosition;
        }
        return iconPosition;
    }

    private int getTabTextSize(Tab item) {
        int textSize = item.getTextSize();
        if (textSize == Tab.USE_TAB_SEGMENT) {
            textSize = mTabTextSize;
        }
        return textSize;
    }

    private int getTabSelectedColor(Tab item) {
        int color = item.getSelectedColor();
        if (color == Tab.USE_TAB_SEGMENT) {
            color = mSelectedColor;
        }
        return color;
    }

    void populateFromPagerAdapter(boolean useAdapterTitle) {
        if (mPagerAdapter == null) {
            if (useAdapterTitle) {
                reset();
            }
            return;
        }
        final int adapterCount = mPagerAdapter.getCount();
        if (useAdapterTitle) {
            reset();
            for (int i = 0; i < adapterCount; i++) {
                addTab(new Tab(mPagerAdapter.getPageTitle(i)));
            }
            notifyDataChanged();
        }

        if (mViewPager != null && adapterCount > 0) {
            final int curItem = mViewPager.getCurrentPage();
            selectTab(curItem, true, false);
        }
    }

    void setPagerAdapter(final PageSliderProvider adapter, boolean useAdapterTitle, final boolean addObserver) {
//        if (mPagerAdapter != null && mPagerAdapterObserver != null) {
//            // If we already have a PagerAdapter, unregister our observer
//            mPagerAdapter.unregisterDataSetObserver(mPagerAdapterObserver);
//        }

        mPagerAdapter = adapter;

//        if (addObserver && adapter != null) {
//            // Register our observer on the new adapter
//            if (mPagerAdapterObserver == null) {
//                mPagerAdapterObserver = new PagerAdapterObserver(useAdapterTitle);
//            }
//            adapter.registerDataSetObserver(mPagerAdapterObserver);
//        }

        // Finally make sure we reflect the new adapter
        populateFromPagerAdapter(useAdapterTitle);
    }

    public int getSelectedIndex() {
        return mCurrentSelectedIndex;
    }

    private int getTabCount() {
        return getAdapter().getSize();
    }

    /**
     * 根据 index 获取对应下标的 {@link Tab} 对象
     *
     * @param index 下标对应的 {@link Tab} 对象
     * @return return
     */
    public Tab getTab(int index) {
        return getAdapter().getItem(index);
    }

    /**
     * 根据 index 在对应的 Tab 上显示未读数或红点
     *
     * @param context context
     * @param index 要显示未读数或红点的 Tab 的下标
     * @param count 不为0时红点会显示该数字作为未读数,为0时只会显示一个小红点
     */
    public void showSignCountView(Context context, int index, int count) {
        Tab tab = getAdapter().getItem(index);
        tab.showSignCountView(context, count);
        notifyDataChanged();
    }

    /**
     * 根据 index 在对应的 Tab 上隐藏红点
     *
     * @param index Tab 的下标
     */
    public void hideSignCountView(int index) {
        Tab tab = getAdapter().getItem(index);
        tab.hideSignCountView();
    }

    /**
     * 获取当前的红点数值，如果没有红点则返回 0
     *
     * @param index Tab 的下标
     * @return return
     */
    public int getSignCount(int index) {
        Tab tab = getAdapter().getItem(index);
        return tab.getSignCount();
    }

    @Override
    public boolean onEstimateSize(int widthMeasureSpec, int heightMeasureSpec) {
        final int widthSize = EstimateSpec.getSize(widthMeasureSpec);
        final int widthMode = EstimateSpec.getSize(widthMeasureSpec);

        if (getChildCount() > 0) {
            final Component child = getComponentAt(0);
            int paddingHor = getPaddingLeft() + getPaddingRight();
            child.estimateSize(EstimateSpec.getSizeWithMode(widthSize - paddingHor, EstimateSpec.PRECISE), heightMeasureSpec);
            if (widthMode == EstimateSpec.NOT_EXCEED) {
                setEstimatedSize(Math.min(widthSize, child.getEstimatedWidth() + paddingHor), heightMeasureSpec);
                return true;
            }
        }
        estimateSize(widthMeasureSpec, heightMeasureSpec);
        return true;
    }

    //    @IntDef(value = {MODE_SCROLLABLE, MODE_FIXED})
    @Retention(RetentionPolicy.SOURCE)
    public @interface Mode {
    }

    //    @IntDef(value = {ICON_POSITION_LEFT, ICON_POSITION_TOP, ICON_POSITION_RIGHT, ICON_POSITION_BOTTOM})
    @Retention(RetentionPolicy.SOURCE)
    public @interface IconPosition {
    }

    public interface OnTabClickListener {
        /**
         * 当某个 Tab 被点击时会触发
         *
         * @param index 被点击的 Tab 下标
         */
        void onTabClick(int index);
    }

    public interface OnTabSelectedListener {
        /**
         * 当某个 Tab 被选中时会触发
         *
         * @param index 被选中的 Tab 下标
         */
        void onTabSelected(int index);

        /**
         * 当某个 Tab 被取消选中时会触发
         *
         * @param index 被取消选中的 Tab 下标
         */
        void onTabUnselected(int index);

        /**
         * 当某个 Tab 处于被选中状态下再次被点击时会触发
         *
         * @param index 被再次点击的 Tab 下标
         */
        void onTabReselected(int index);

        /**
         * 当某个 Tab 被双击时会触发
         *
         * @param index 被双击的 Tab 下标
         */
        void onDoubleTap(int index);
    }

    public interface TypefaceProvider {

        boolean isNormalTabBold();

        boolean isSelectedTabBold();

        Font getTypeface();
    }

    public static class TabLayoutOnPageChangeListener implements PageSlider.PageChangedListener {
        private final WeakReference<TabSegment> mTabSegmentRef;

        public TabLayoutOnPageChangeListener(TabSegment tabSegment) {
            mTabSegmentRef = new WeakReference<>(tabSegment);
        }

        @Override
        public void onPageSliding(final int position, final float positionOffset,
                                  final int positionOffsetPixels) {
//            final TabSegment tabSegment = mTabSegmentRef.get();
//            if (tabSegment != null) {
//                tabSegment.updateIndicatorPosition(position, positionOffset);
//            }
        }

        @Override
        public void onPageSlideStateChanged(int state) {
            final TabSegment tabSegment = mTabSegmentRef.get();
            if (tabSegment != null) {
                tabSegment.setViewPagerScrollState(state);
            }
        }

        @Override
        public void onPageChosen(int position) {
            final TabSegment tabSegment = mTabSegmentRef.get();
            if (tabSegment != null && tabSegment.getSelectedIndex() != position
                && position < tabSegment.getTabCount()) {
                tabSegment.selectTab(position, true, false);
            }
        }
    }

    private static class ViewPagerOnTabSelectedListener implements OnTabSelectedListener {
        private final PageSlider mViewPager;

        public ViewPagerOnTabSelectedListener(PageSlider viewPager) {
            mViewPager = viewPager;
        }

        @Override
        public void onTabSelected(int index) {
            mViewPager.setCurrentPage(index, false);
        }

        @Override
        public void onTabUnselected(int index) {
        }

        @Override
        public void onTabReselected(int index) {
        }

        @Override
        public void onDoubleTap(int index) {

        }
    }

    public static class Tab {
        public static final int USE_TAB_SEGMENT = Integer.MIN_VALUE;
        private int textSize = USE_TAB_SEGMENT;
        private int normalColor = USE_TAB_SEGMENT;
        private int selectedColor = USE_TAB_SEGMENT;
        private PixelMapElement normalIcon = null;
        private PixelMapElement selectedIcon = null;
        private int contentWidth = 0;
        private int contentLeft = 0;
        private int iconPosition = USE_TAB_SEGMENT;
        private int gravity = LayoutAlignment.CENTER;
        private CharSequence text;
        private List<Component> mCustomViews;
        private int mSignCountDigits = 2;
        private Text mSignCountTextView;
        private int mSignCountMarginLeft = 0;
        private int mSignCountMarginTop = 0;
        /**
         * 是否动态更改icon颜色，如果为true, selectedIcon将失效
         */
        private boolean dynamicChangeIconColor = true;

        public Tab(CharSequence text) {
            this.text = text;
        }


        public Tab(PixelMapElement normalIcon, PixelMapElement selectedIcon, CharSequence text, boolean dynamicChangeIconColor) {
            this(normalIcon, selectedIcon, text, dynamicChangeIconColor, true);
        }

        /**
         * 如果你的 icon 显示大小和实际大小不吻合:
         * 1. 设置icon 的 bounds
         * 2. 使用此构造器
         * 3. 最后一个参数（setIntrinsicSize）设置为false
         *
         * @param normalIcon 未选中态 icon
         * @param selectedIcon 选中态 icon
         * @param text 文字
         * @param dynamicChangeIconColor 是否动态改变 icon 颜色
         * @param setIntrinsicSize 是否设置 icon 的大小为 intrinsic width 和 intrinsic height。
         */
        public Tab(PixelMapElement normalIcon, PixelMapElement selectedIcon, CharSequence text, boolean dynamicChangeIconColor, boolean setIntrinsicSize) {
            this.normalIcon = normalIcon;
//            if (this.normalIcon != null && setIntrinsicSize) {
//                this.normalIcon.setBounds(0, 0, normalIcon.getIntrinsicWidth(), normalIcon.getIntrinsicHeight());
//            }
            this.selectedIcon = selectedIcon;
//            if (this.selectedIcon != null && setIntrinsicSize) {
//                this.selectedIcon.setBounds(0, 0, selectedIcon.getIntrinsicWidth(), selectedIcon.getIntrinsicHeight());
//            }
            this.text = text;
            this.dynamicChangeIconColor = dynamicChangeIconColor;
        }

        /**
         * 设置红点中数字显示的最大位数，默认值为 2，超过这个位数以 99+ 这种形式显示。如：110 -> 99+，98 -> 98
         *
         * @param digit 数字显示的最大位数
         */
        public void setmSignCountDigits(int digit) {
            mSignCountDigits = digit;
        }

        public void setTextColor(int normalColor, int selectedColor) {
            this.normalColor = normalColor;
            this.selectedColor = selectedColor;
        }

        public int getTextSize() {
            return textSize;
        }

        public void setTextSize(int textSize) {
            this.textSize = textSize;
        }

        public CharSequence getText() {
            return text;
        }

        public void setText(CharSequence text) {
            this.text = text;
        }

        public int getContentLeft() {
            return contentLeft;
        }

        public void setContentLeft(int contentLeft) {
            this.contentLeft = contentLeft;
        }

        public int getContentWidth() {
            return contentWidth;
        }

        public void setContentWidth(int contentWidth) {
            this.contentWidth = contentWidth;
        }

        public int getIconPosition() {
            return iconPosition;
        }

        public void setIconPosition(int iconPosition) {
            this.iconPosition = iconPosition;
        }

        public int getGravity() {
            return gravity;
        }

        public void setGravity(int gravity) {
            this.gravity = gravity;
        }

        public int getNormalColor() {
            return normalColor;
        }

        public PixelMapElement getNormalIcon() {
            return normalIcon;
        }

        public int getSelectedColor() {
            return selectedColor;
        }

        public PixelMapElement getSelectedIcon() {
            return selectedIcon;
        }

        public boolean isDynamicChangeIconColor() {
            return dynamicChangeIconColor;
        }

        private void addCustomView(Component view) {
            if (mCustomViews == null) {
                mCustomViews = new ArrayList<>();
            }
            if (view.getLayoutConfig() == null) {
                view.setLayoutConfig(getDefaultCustomLayoutParam());
            }
            mCustomViews.add(view);
        }

        public List<Component> getCustomViews() {
            return mCustomViews;
        }

        /**
         * 设置红点的位置, 注意红点的默认位置是在内容的右侧并顶对齐
         *
         * @param marginLeft 在红点默认位置的基础上添加的 marginLeft
         * @param marginTop 在红点默认位置的基础上添加的 marginTop
         */
        public void setSignCountMargin(int marginLeft, int marginTop) {
            mSignCountMarginLeft = marginLeft;
            mSignCountMarginTop = marginTop;
            if (mSignCountTextView != null && mSignCountTextView.getLayoutConfig() != null) {
                mSignCountTextView.getLayoutConfig().setMarginLeft(marginLeft);
                mSignCountTextView.getLayoutConfig().setMarginTop(marginTop);
            }
        }

        private Text ensureSignCountView(Context context) {
            if (mSignCountTextView == null) {
                mSignCountTextView = new Text(context);
                mSignCountTextView.setBackground(new ShapeElement(context, ResourceTable.Graphic_xui_sign_count_view_bg));
                mSignCountTextView.setTextColor(Color.WHITE);
                mSignCountTextView.setTextSize(14, Text.TextSizeType.FP);
                mSignCountTextView.setTextAlignment(TextAlignment.CENTER);
                DependentLayout.LayoutConfig signCountLp = new DependentLayout.LayoutConfig(ComponentContainer.LayoutConfig.MATCH_CONTENT,
                    AttrHelper.vp2px(ElementHelper.getFloat(context, ResourceTable.Float_xui_tab_sign_count_view_minSize), context));
                signCountLp.addRule(DependentLayout.LayoutConfig.ALIGN_TOP, ID_TAB_ITEM_VIEW);
                signCountLp.addRule(DependentLayout.LayoutConfig.RIGHT_OF, ID_TAB_ITEM_VIEW);
                mSignCountTextView.setLayoutConfig(signCountLp);
                addCustomView(mSignCountTextView);
            }
            // 确保在先 setMargin 后 create 的情况下 margin 会生效
            setSignCountMargin(mSignCountMarginLeft, mSignCountMarginTop);
            return mSignCountTextView;
        }

        /**
         * 显示 Tab 上的未读数或红点
         *
         * @param context context
         * @param count 不为0时红点会显示该数字作为未读数,为0时只会显示一个小红点
         */
        public void showSignCountView(Context context, int count) {
            ensureSignCountView(context);
            mSignCountTextView.setVisibility(Component.VISIBLE);
            DependentLayout.LayoutConfig signCountLp = (DependentLayout.LayoutConfig) mSignCountTextView.getLayoutConfig();
            if (count != 0) {
                int height = AttrHelper.vp2px(ElementHelper.getFloat(context, ResourceTable.Float_xui_tab_sign_count_view_minSize_with_text), context);
                // 显示未读数
                signCountLp.height = height;
                mSignCountTextView.setLayoutConfig(signCountLp);
                mSignCountTextView.setMinHeight(height);
                mSignCountTextView.setMinWidth(height);
                mSignCountTextView.setText(getNumberDigitsFormattingValue(count));
            } else {
                int height = AttrHelper.vp2px(ElementHelper.getFloat(context, ResourceTable.Float_xui_tab_sign_count_view_minSize), context);
                // 显示红点
                signCountLp.height = height;
                mSignCountTextView.setLayoutConfig(signCountLp);
                mSignCountTextView.setMinHeight(height);
                mSignCountTextView.setMinWidth(height);
                mSignCountTextView.setText(null);
            }
        }

        /**
         * 隐藏 Tab 上的未读数或红点
         */
        public void hideSignCountView() {
            if (mSignCountTextView != null) {
                mSignCountTextView.setVisibility(Component.HIDE);
            }
        }

        /**
         * 获取该 Tab 的未读数
         *
         * @return return
         */
        public int getSignCount() {
            if (mSignCountTextView == null || mSignCountTextView.getVisibility() != VISIBLE) {
                return 0;
            }
            if (!Utils.isNullOrEmpty(mSignCountTextView.getText())) {
                return Integer.parseInt(mSignCountTextView.getText().toString());
            } else {
                return 0;
            }
        }

        private DependentLayout.LayoutConfig getDefaultCustomLayoutParam() {
            return new DependentLayout.LayoutConfig(LayoutConfig.MATCH_CONTENT, LayoutConfig.MATCH_CONTENT);
        }

        private String getNumberDigitsFormattingValue(int number) {
            if (Utils.getNumberDigits(number) > mSignCountDigits) {
                StringBuilder result = new StringBuilder();
                for (int digit = 1; digit <= mSignCountDigits; digit++) {
                    result.append("9");
                }
                result.append("+");
                return result.toString();
            } else {
                return String.valueOf(number);
            }
        }
    }

    public class TabAdapter extends XUIItemViewsAdapter<Tab, TabItemView> {
        public TabAdapter(ComponentContainer parentView) {
            super(parentView);
        }

        @Override
        protected TabItemView createView(ComponentContainer parentView) {
            return new TabItemView(getContext());
        }

        @Override
        protected void bind(Tab item, TabItemView view, int position) {
            Text tv = view.getTextView();
            setTextViewTypeface(tv, false);
            // custom view
            List<Component> mCustomViews = item.getCustomViews();
            if (mCustomViews != null && mCustomViews.size() > 0) {
//                view.setTag(R.id.xui_view_can_not_cache_tag, true);
                for (Component v : mCustomViews) {
                    // 防止先 setCustomViews 然后再 updateTabText 时会重复添加 customView 导致 crash
                    if (v.getComponentParent() == null) {
                        view.addComponent(v);
                    }
                }
            }
            // gravity
            if (mMode == MODE_FIXED) {
                int gravity = item.getGravity();
                DependentLayout.LayoutConfig lp = (DependentLayout.LayoutConfig) tv.getLayoutConfig();
                lp.addRule(DependentLayout.LayoutConfig.ALIGN_PARENT_LEFT,
                    (gravity & LayoutAlignment.LEFT) == LayoutAlignment.LEFT ? DependentLayout.LayoutConfig.TRUE : 0);
                lp.addRule(DependentLayout.LayoutConfig.HORIZONTAL_CENTER,
                    (gravity & LayoutAlignment.CENTER) == LayoutAlignment.CENTER ? DependentLayout.LayoutConfig.TRUE : 0);
                lp.addRule(DependentLayout.LayoutConfig.ALIGN_PARENT_RIGHT,
                    (gravity & LayoutAlignment.RIGHT) == LayoutAlignment.RIGHT ? DependentLayout.LayoutConfig.TRUE : 0);
                tv.setLayoutConfig(lp);
            }

            tv.setText(item.getText().toString());
            tv.setTextSize(getTabTextSize(item), Text.TextSizeType.FP);
            view.updateDecoration(item, mCurrentSelectedIndex == position);
            view.setTag(position);
            view.setClickedListener(mTabOnClickListener);
        }
    }

//    private class AdapterChangeListener implements PageSlider.OnAdapterChangeListener {
//        private boolean mAutoRefresh;
//        private final boolean mUseAdapterTitle;
//
//        AdapterChangeListener(boolean useAdapterTitle) {
//            mUseAdapterTitle = useAdapterTitle;
//        }
//
//        @Override
//        public void onAdapterChanged(@NonNull ViewPager viewPager,
//                                     @Nullable PagerAdapter oldAdapter, @Nullable PagerAdapter newAdapter) {
//            if (mViewPager == viewPager) {
//                setPagerAdapter(newAdapter, mUseAdapterTitle, mAutoRefresh);
//            }
//        }
//
//        void setAutoRefresh(boolean autoRefresh) {
//            mAutoRefresh = autoRefresh;
//        }
//    }

    public class TabItemView extends DependentLayout {
        private Text mTextView;

        public TabItemView(Context context) {
            super(context);
            mTextView = new Text(getContext());
            mTextView.setMaxTextLines(1);
            mTextView.setTextAlignment(TextAlignment.CENTER);
            mTextView.setTruncationMode(Text.TruncationMode.ELLIPSIS_AT_MIDDLE);
//            mTextView.setTypeface(XUI.getDefaultTypeface());
            // 用于提供给customView布局用
            mTextView.setId(ID_TAB_ITEM_VIEW);
            LayoutConfig tvLp = new LayoutConfig(ComponentContainer.LayoutConfig.MATCH_CONTENT,
                ComponentContainer.LayoutConfig.MATCH_CONTENT);
            tvLp.addRule(LayoutConfig.VERTICAL_CENTER, LayoutConfig.TRUE);
            addComponent(mTextView, tvLp);
        }

        public Text getTextView() {
            return mTextView;
        }

        /**
         * 更改图片颜色
         *
         * @param element
         * @param maskColor
         */
        private void setColorTint(Element element, int maskColor) {
            // 忽略透明度时的颜色矩阵
            float r = Color.alpha(maskColor) / 255f;
            r = r - (1 - r) * 0.15f;
            float rr = (1 - r) * 1.15f;
            ColorMatrix colorMatrix = new ColorMatrix();
            colorMatrix.setMatrix(new float[]{
                rr, 0, 0, 0, ((maskColor >> 16) & 0xFF) * r,
                0, rr, 0, 0, ((maskColor >> 8) & 0xFF) * r,
                0, 0, rr, 0, (maskColor & 0xFF) * r,
                0, 0, 0, 1, 0,
            });
            element.setColorMatrix(colorMatrix);
        }

        public void setColorInTransition(Tab tab, int color) {
            mTextView.setTextColor(new Color(color));
            if (tab.isDynamicChangeIconColor()) {
                Element icon = mTextView.getAroundElements()[getTabIconPosition(tab)];
                if (icon != null) {
                    setColorTint(icon, color);
                    setDrawable(mTextView, icon, getTabIconPosition(tab));
                }
            }
        }

        public void updateDecoration(Tab tab, boolean isSelected) {
            int color = isSelected ? getTabSelectedColor(tab) : getTabNormalColor(tab);
            mTextView.setTextColor(new Color(color));
            PixelMapElement icon = tab.getNormalIcon();
            if (isSelected) {
                if (!tab.isDynamicChangeIconColor()) {
                    icon = tab.getSelectedIcon() != null ? tab.getSelectedIcon() : icon;
                } else if (icon != null) {
                    setColorTint(icon, color);
                }
            }

            if (icon == null) {
                mTextView.setAroundElementsPadding(0);
                mTextView.setAroundElements(null, null, null, null);
            } else {
                mTextView.setAroundElementsPadding(AttrHelper.vp2px(4, getContext()));
                setDrawable(mTextView, icon, getTabIconPosition(tab));
            }
        }
    }
//
//    private class PagerAdapterObserver extends DataSetObserver {
//        private final boolean mUseAdapterTitle;
//
//        PagerAdapterObserver(boolean useAdapterTitle) {
//            mUseAdapterTitle = useAdapterTitle;
//        }
//
//        @Override
//        public void onChanged() {
//            populateFromPagerAdapter(mUseAdapterTitle);
//        }
//
//        @Override
//        public void onInvalidated() {
//            populateFromPagerAdapter(mUseAdapterTitle);
//        }
//    }

    private final class Container extends ComponentContainer {
        private TabAdapter mTabAdapter;

        public Container(Context context) {
            super(context);
            mTabAdapter = new TabAdapter(this);
            init();
        }

        public TabAdapter getTabAdapter() {
            return mTabAdapter;
        }

        private void init() {
            setEstimateSizeListener(new EstimateSizeListener() {
                @Override
                public boolean onEstimateSize(int widthMeasureSpec, int heightMeasureSpec) {
                    int widthSpecSize = EstimateSpec.getSize(widthMeasureSpec);
                    int heightSpecSize = EstimateSpec.getSize(heightMeasureSpec);
                    List<TabItemView> childViews = mTabAdapter.getViews();
                    int size = childViews.size();
                    int i;

                    int visibleChild = 0;
                    for (i = 0; i < size; i++) {
                        Component child = childViews.get(i);
                        if (child.getVisibility() == VISIBLE) {
                            visibleChild++;
                        }
                    }
                    if (size == 0 || visibleChild == 0) {
                        setEstimatedSize(widthSpecSize, heightSpecSize);
                        return true;
                    }

                    int childHeight = heightSpecSize - getPaddingTop() - getPaddingBottom();
                    int childWidthMeasureSpec, childHeightMeasureSpec, resultWidthSize = 0;
                    if (mMode == MODE_FIXED) {
                        resultWidthSize = widthSpecSize;
                        int modeFixItemWidth = widthSpecSize / visibleChild;
                        for (i = 0; i < size; i++) {
                            final Component child = childViews.get(i);
                            if (child.getVisibility() != VISIBLE) {
                                continue;
                            }
                            childWidthMeasureSpec = EstimateSpec.getSizeWithMode(modeFixItemWidth, EstimateSpec.PRECISE);
                            childHeightMeasureSpec = EstimateSpec.getSizeWithMode(childHeight, EstimateSpec.PRECISE);
                            child.estimateSize(childWidthMeasureSpec, childHeightMeasureSpec);
                        }
                    } else {
                        for (i = 0; i < size; i++) {
                            final Component child = childViews.get(i);
                            if (child.getVisibility() != VISIBLE) {
                                continue;
                            }
                            childWidthMeasureSpec = EstimateSpec.getSizeWithMode(widthSpecSize, EstimateSpec.NOT_EXCEED);
                            childHeightMeasureSpec = EstimateSpec.getSizeWithMode(childHeight, EstimateSpec.PRECISE);
                            child.estimateSize(childWidthMeasureSpec, childHeightMeasureSpec);
                            resultWidthSize += child.getEstimatedWidth() + mItemSpaceInScrollMode;
                        }
                        resultWidthSize -= mItemSpaceInScrollMode;
                        ComponentContainer parent = (ComponentContainer) getComponentParent();
                        resultWidthSize += parent.getPaddingLeft() + parent.getPaddingRight();
                    }
                    setEstimatedSize(resultWidthSize, heightSpecSize);
                    return true;
                }
            });
            setLayoutRefreshedListener(new LayoutRefreshedListener() {
                @Override
                public void onRefreshed(Component component) {
                    int b = component.getBottom();
                    int t = component.getTop();
                    List<TabItemView> childViews = mTabAdapter.getViews();
                    int size = childViews.size();
                    int i;
                    int visibleChild = 0;
                    for (i = 0; i < size; i++) {
                        Component child = childViews.get(i);
                        if (child.getVisibility() == VISIBLE) {
                            visibleChild++;
                        }
                    }

                    if (size == 0 || visibleChild == 0) {
                        return;
                    }

                    int usedLeft = getPaddingLeft();
                    for (i = 0; i < size; i++) {
                        TabItemView childView = childViews.get(i);
                        if (childView.getVisibility() != VISIBLE) {
                            continue;
                        }

                        int childMeasureWidth = childView.getEstimatedWidth();
                        childView.arrange(usedLeft, getPaddingTop(), usedLeft + childMeasureWidth, b - t - getPaddingBottom());

                        Tab model = mTabAdapter.getItem(i);
                        int oldLeft, oldWidth, newLeft, newWidth;
                        oldLeft = model.getContentLeft();
                        oldWidth = model.getContentWidth();
                        if (mMode == MODE_FIXED && mIsIndicatorWidthFollowContent) {
                            Text contentView = childView.getTextView();
                            newLeft = usedLeft + contentView.getLeft();
                            newWidth = contentView.getWidth();
                        } else {
                            newLeft = usedLeft;
                            newWidth = childMeasureWidth;
                        }
                        if (oldLeft != newLeft || oldWidth != newWidth) {
                            model.setContentLeft(newLeft);
                            model.setContentWidth(newWidth);
                        }
                        usedLeft = usedLeft + childMeasureWidth + (mMode == MODE_SCROLLABLE ? mItemSpaceInScrollMode : 0);
                    }
                    if (mCurrentSelectedIndex != NO_POSITION && mSelectAnimator == null
                        && mViewPagerScrollState == PageSlider.SCROLL_IDLE_STAGE) {
                        if (isModeFixedFirst && mViewPager != null) {
                            layoutIndicator(mTabAdapter.getItem(mCurrentSelectedIndex), true);
                            isModeFixedFirst = false;
                        } else {
                            layoutIndicator(mTabAdapter.getItem(mCurrentSelectedIndex), false);
                        }
                    }
                }
            });
            addDrawTask(new DrawTask() {
                @Override
                public void onDraw(Component component, Canvas canvas) {
                    dispatchDraw(canvas);
                }
            });
        }

        protected void dispatchDraw(Canvas canvas) {
            if (mHasIndicator && mIndicatorRect != null) {
                if (mIndicatorTop) {
                    mIndicatorRect.top = getPaddingTop();
                    mIndicatorRect.bottom = mIndicatorRect.top + mIndicatorHeight;
                } else {
                    mIndicatorRect.bottom = getHeight() - getPaddingBottom();
                    mIndicatorRect.top = mIndicatorRect.bottom - mIndicatorHeight;
                }
                if (mIndicatorDrawable != null) {
                    mIndicatorDrawable.setBounds(mIndicatorRect);
                    mIndicatorDrawable.drawToCanvas(canvas);
                } else {
                    canvas.drawRect(mIndicatorRect, mIndicatorPaint);
                }
            }
        }
    }
}
